home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / fillOp.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  8KB  |  325 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/StringDefs.h>
  17. #include <X11/cursorfont.h>
  18. #ifndef NOSTDHDRS
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #endif
  22. #include "Paint.h"
  23. #include "misc.h"
  24. #include "xpaint.h"
  25.  
  26. typedef struct {
  27.     Boolean        done;
  28. } LocalInfo;
  29.  
  30. #define ZINDEX8(x, y, img)  ((y) * img->bytes_per_line) + (x)
  31.  
  32. static Drawable    drawable;
  33. static Display    *dpy;
  34. static XImage    *source;
  35. static Boolean    *mask;
  36. static int    maskW, maskH;
  37. static int    xMin, yMin, xMax, yMax;
  38. static int    timeCount = 0;
  39. static int    fillMode = 0;
  40.  
  41.  
  42. /*
  43.  * A Seed Fill Algorithm
  44.  * by Paul Heckbert
  45.  * from "Graphics Gems", Academic Press, 1990
  46.  */
  47.  
  48. /*
  49.  * fill.c : simple seed fill program
  50.  * Calls pixelread() to read pixels, pixelwrite() to write pixels.
  51.  *
  52.  * Paul Heckbert        13 Sept 1982, 28 Jan 1987
  53.  */
  54.  
  55. #define pixelwrite(x,y)    do {             \
  56.         mask[y * maskW + x] = True;    \
  57.         xMin = MIN(xMin, x);        \
  58.         yMin = MIN(yMin, y);        \
  59.         xMax = MAX(xMax, x);        \
  60.         yMax = MAX(yMax, y);        \
  61.     } while (0)
  62.  
  63. #define STEP    32
  64.  
  65. static Pixel pixelread(int x, int y, Boolean first)
  66. {
  67.     static Pixel    ov;
  68.     static int    xMin, yMin, xMax, yMax;
  69.     Pixel        p;
  70.     int        n;
  71.  
  72.     if (first) {
  73.         xMin = MAX(x - STEP, 0);
  74.         yMin = MAX(y - STEP, 0);
  75.         xMax = MIN(x + STEP, maskW);
  76.         yMax = MIN(y + STEP, maskH);
  77.  
  78.         XGetSubImage(dpy, drawable, xMin, yMin,
  79.                 xMax - xMin, yMax - yMin,
  80.                 AllPlanes, ZPixmap, source,
  81.                 xMin, yMin);
  82.  
  83.         ov = XGetPixel(source, x, y);
  84.  
  85.         return ov;
  86.     } else if (mask[y * maskW + x]) {
  87.         return ~ov;
  88.     }
  89.  
  90.     if (x < xMin) {
  91.         n = MAX(x - STEP, 0);
  92.         XGetSubImage(dpy, drawable, n, yMin,
  93.                 xMin - n, yMax - yMin,
  94.                 AllPlanes, ZPixmap, source,
  95.                 n, yMin);
  96.         xMin = n;
  97.     }
  98.     if (y < yMin) {
  99.         n = MAX(y - STEP, 0);
  100.         XGetSubImage(dpy, drawable, xMin, n,
  101.                 xMax - xMin, yMin - n,
  102.                 AllPlanes, ZPixmap, source,
  103.                 xMin, n);
  104.         yMin = n;
  105.     }
  106.     if (x >= xMax) {
  107.         n = MIN(x + STEP, maskW);
  108.         XGetSubImage(dpy, drawable, xMax, yMin,
  109.                 n - xMax, yMax - yMin,
  110.                 AllPlanes, ZPixmap, source,
  111.                 xMax, yMin);
  112.         xMax = n;
  113.     }
  114.     if (y >= yMax) {
  115.         n = MIN(y + STEP, maskH);
  116.         XGetSubImage(dpy, drawable, xMin, yMax,
  117.                 xMax - xMin, n - yMax,
  118.                 AllPlanes, ZPixmap, source,
  119.                 xMin, yMax);
  120.         yMax = n;
  121.     }
  122.     
  123.     /*
  124.     **  Do it fast for those 8 bit displays...
  125.     */
  126.     if (source->bits_per_pixel == 8) {
  127.         p = source->data[ZINDEX8(x, y, source)]; 
  128.     } else {
  129.         p = XGetPixel(source, x, y);
  130.     }
  131.     return p;
  132. }
  133.  
  134. /*
  135. **  Exange pixel 1 for filled pixel value 2
  136. */
  137. static void change(int sx, int sy, int width, int height)
  138. {
  139.     int    x, y;
  140.     Pixel    pix = XGetPixel(source, sx, sy);
  141.  
  142.     if (source->bits_per_pixel == 8) {
  143.         for (y = 0; y < height; y++) {
  144.             for (x = 0; x < width; x++)
  145.                 if (source->data[ZINDEX8(x, y, source)] == pix)
  146.                     pixelwrite(x, y);
  147.             if (y % 100 == 0)
  148.                 StateTimeStep();
  149.         }
  150.     } else {
  151.         for (y = 0; y < height; y++) {
  152.             for (x = 0; x < width; x++)
  153.                 if (XGetPixel(source, x, y) == pix)
  154.                     pixelwrite(x, y);
  155.             if (y % 64 == 0)
  156.                 StateTimeStep();
  157.         }
  158.     }
  159. }
  160.  
  161. typedef struct {short y, xl, xr, dy;} Segment;
  162. /*
  163.  * Filled horizontal segment of scanline y for xl<=x<=xr.
  164.  * Parent segment was on line y-dy.  dy=1 or -1
  165.  */
  166.  
  167. #define STACKSIZE 20000              /* max depth of stack */
  168.  
  169. #define PUSH(Y, XL, XR, DY)  /* push new segment on stack */ \
  170.     if (sp<stack+STACKSIZE && Y+(DY)>=0 && Y+(DY)<=height) \
  171.     {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
  172.  
  173. #define POP(Y, XL, XR, DY)    /* pop segment off stack */ \
  174.     {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
  175.  
  176. /*
  177.  * fill: set the pixel at (x,y) and all of its 4-connected neighbors
  178.  * with the same pixel value to the new pixel value nv.
  179.  * A 4-connected neighbor is a pixel above, below, left, or right of a pixel.
  180.  */
  181.  
  182. static void fill(int x, int y, int width, int height)
  183. {
  184.     int start, x1, x2, dy = 0;
  185.     Pixel ov;      /* old pixel value */
  186.     Segment stack[STACKSIZE], *sp = stack;   /* stack of filled segments */
  187.  
  188.     ov = pixelread(x, y, True);              /* read pv at seed point */
  189.     PUSH(y, x, x, 1);                      /* needed in some cases */
  190.     PUSH(y+1, x, x, -1);                /* seed segment (popped 1st) */
  191.  
  192.     while (sp>stack) {
  193.         /* pop segment off stack and fill a neighboring scan line */
  194.         POP(y, x1, x2, dy);
  195.         /*
  196.          * segment of scan line y-dy for x1<=x<=x2 was previously filled,
  197.          */
  198.         for (x = x1; x >= 0 && pixelread(x, y, False) == ov; x--)
  199.             pixelwrite(x, y);
  200.         if (x >= x1) {
  201.           for (x++; x<=x2 && pixelread(x, y, False)!=ov; x++);
  202.           start = x;
  203.       if (x > x2)
  204.         continue;
  205.     } else {
  206.           start = x+1;
  207.           if (start<x1) PUSH(y, start, x1-1, -dy);       /* leak on left? */
  208.           x = x1+1;
  209.     }
  210.         do {
  211.             for (; x<=width && pixelread(x, y, False)==ov; x++)
  212.                 pixelwrite(x, y);
  213.             PUSH(y, start, x-1, dy);
  214.             if (x>x2+1) PUSH(y, x2+1, x-1, -dy);       /* leak on right? */
  215.             for (x++; x<=x2 && pixelread(x, y, False)!=ov; x++);
  216.             start = x;
  217.         } while (x<=x2);
  218.  
  219.     if (++timeCount % 32 == 0) 
  220.         StateTimeStep();
  221.     }
  222. }
  223.  
  224. static void     press(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info)
  225. {
  226.     XRectangle    undo, rect;
  227.     int        width, height;
  228.     GC        gc, dgc;
  229.     XGCValues    values;
  230.     int        isBusy, depth;
  231.     Pixmap        pix;
  232.  
  233.     if (event->button == Button1)
  234.         dgc = info->first_gc;
  235.     else if (event->button == Button2)
  236.         dgc = info->second_gc;
  237.     else
  238.         return;
  239.  
  240.     dpy = XtDisplay(w);
  241.     drawable = info->drawable;
  242.  
  243.     UndoStart(w, info);
  244.  
  245.     XtVaGetValues(w, XtNdrawWidth, &width, 
  246.              XtNdrawHeight, &height, 
  247.              XtNdepth, &depth, 
  248.              NULL);
  249.     if (isBusy = (width * height > 6400))
  250.         StateSetBusy(True);
  251.  
  252.     if ((mask = (Boolean*)XtCalloc(sizeof(Boolean), width * height)) == NULL)
  253.         return;
  254.     maskW = width;
  255.     maskH = height;
  256.     
  257.     memset(mask, False, width * height * sizeof(Boolean));
  258.  
  259.     if (fillMode == 0) {
  260.         source = NewXImage(dpy, NULL, depth, width, height);
  261.     } else {
  262.         source = PwGetImage(w, NULL);
  263.     }
  264.  
  265.     xMin = xMax = info->realX;
  266.     yMin = yMax = info->realY;
  267.  
  268.     if (fillMode == 0)
  269.         fill(info->realX, info->realY, width - 1, height - 1);
  270.     else
  271.         change(info->realX, info->realY, width, height);
  272.  
  273.     rect.x      = xMin;
  274.     rect.y      = yMin;
  275.     rect.width  = (xMax - xMin) + 1;
  276.     rect.height = (yMax - yMin) + 1;
  277.  
  278.     pix = MaskDataToPixmap(w, width, height, mask, &rect);
  279.  
  280.     XSetClipOrigin(dpy, dgc, rect.x, rect.y);
  281.     XSetClipMask(dpy, dgc, pix);
  282.  
  283.     XFillRectangles(dpy, info->drawable, dgc, &rect, 1);
  284.  
  285.     if (!info->isFat)
  286.         XFillRectangles(dpy, XtWindow(w), dgc, &rect, 1);
  287.  
  288.     XSetClipMask(dpy, dgc, None);
  289.     XFreePixmap(dpy, pix);
  290.  
  291.     XYtoRECT(xMin, yMin, xMax + 1, yMax + 1, &undo);
  292.     UndoSetRectangle(w, &undo);
  293.     PwUpdate(w, &undo, False);
  294.  
  295.     if (fillMode == 0)
  296.         XDestroyImage(source);
  297.  
  298.     if (isBusy)
  299.         StateSetBusy(False);
  300. }
  301.  
  302. void *FillAdd(Widget w)
  303. {
  304.     LocalInfo    *l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));
  305.     l->done = False;
  306.     OpAddEventHandler(w, opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
  307.     SetCrossHairCursor(w);
  308.     return l;
  309. }
  310. void FillRemove(Widget w, LocalInfo *l)
  311. {
  312.     OpRemoveEventHandler(w, opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
  313.     XtFree((XtPointer)l);
  314. }
  315.  
  316. void FillSetMode(int value)
  317. {
  318.     fillMode = value;
  319. }
  320.  
  321. int FillGetMode()
  322. {
  323.     return fillMode;
  324. }
  325.